/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Optimizacion;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import Data.*;
import Traductor.*;

/**
 *
 * @author REI
 */
public class Optimizador extends ListaBloques{
    
    OptimizacionMirilla mirilla = new OptimizacionMirilla();
    OptimizacionBloque op_bloques = new OptimizacionBloque();
    int copia = 0;
    int grafo_original = 0;

    public void IniciarOptimizacion(File file) {

        if (file.exists()) {
            try {
                

                    boolean repetir_ciclo = true;
                    while (repetir_ciclo == true) {
                        int control_final = 0;

                        boolean optimizar_por_mirilla = true;
                        while (optimizar_por_mirilla == true) {
                            int control = 0;//para revisar si se vuelve a pasar mirilla
                            boolean repetir = true;
                            while (repetir == true) {
                                System.out.println("OPTIMIZACION M1 ------------------------------------------------");
                                repetir = optimizacion_mirilla_1(file);
                                control++;
                            }
                            copia = 0;
                            repetir = true;
                            while (repetir == true) {
                                System.out.println("OPTIMIZACION M2 ------------------------------------------------");
                                repetir = optimizacion_mirilla_2(file);
                                control++;
                            }

                            copia = 0;
                            repetir = true;
                            while (repetir == true) {
                                System.out.println("OPTIMIZACION M3 ------------------------------------------------");
                                repetir = optimizacion_mirilla_3(file);
                                control++;
                            }

                            copia = 0;
                            repetir = true;
                            while (repetir == true) {
                                System.out.println("OPTIMIZACION M4 ------------------------------------------------");
                                repetir = optimizacion_mirilla_4(file);
                                control++;
                            }

                            //si alguna optimizacion se hizo mas de una vez, continua el ciclo de optimizar por mirilla
                            if (control == 4) {//si los 4 tipos de optimizacion por mirilla se hizo solamente una vez, para el ciclo de la optimizacion por mirilla
                                optimizar_por_mirilla = false;
                            }
                            control_final++;
                        }

                        
                        if(control_final<4){
                            repetir_ciclo = false;
                        }else{
                            if(control_final== 4){
                                //1 por el ciclo de mirillas
                                // 3 por las optimizaciones de bloques
                                repetir_ciclo = false;
                            }
                        }
//                        repetir_ciclo=false;
                    }
              
                    
                
            } catch (IOException ex) {
                System.out.println("crear 3d");
                Logger.getLogger(Optimizador.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            JOptionPane.showMessageDialog(null, "No existe archivo con ese nombre", "Mensaje de Error", JOptionPane.ERROR_MESSAGE);    //No existe
        }
    }

    public void reescribir_archivo(File file, parsero optimo1) {
        BufferedWriter salida = null;
        try {
            salida = new BufferedWriter(new FileWriter(file));
        } catch (IOException ex) {
            Logger.getLogger(Optimizador.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("salida");
        }

        String texto = "";

        Iterator m1 = optimo1.getGlobales().iterator();
        while (m1.hasNext()) {
            //System.out.println(m1.next());
            texto = texto + m1.next() + "\n";
            if(texto.contains("stack"))
            {
                System.out.println("error en globaless***********************************************************");
            }
        }

        m1 = optimo1.getListaFunciones().iterator();
        while (m1.hasNext()) {
            NodoMirilla aux = (NodoMirilla) m1.next();
            //System.out.println(aux.getLinea()+" {");
            texto = texto + aux.getLinea() + "{\n";
            Iterator m2 = aux.getLista().iterator();
            while (m2.hasNext()) {
                //System.out.println(m2.next());
                texto = texto + m2.next() + "\n";
                if(texto.contains("stack"))
                {
                    System.out.println("error en funciones***********************************************************");
                }
            }
            //System.out.println("}");
            texto = texto + "}\n\n";
        }
        try {
            salida.write(texto);
            if (salida != null) {
                salida.flush();
                salida.close();
            }
        } catch (IOException ex) {
            Logger.getLogger(Optimizador.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void reescribir_archivo_bloques(File file, ArrayList<NodoGrafo> lista_grafos) {

        BufferedWriter salida = null;
        try {
            salida = new BufferedWriter(new FileWriter(file));
        } catch (IOException ex) {
            Logger.getLogger(Optimizador.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("salida");
        }

        String texto = "";
        for (NodoGrafo aux : lista_grafos) {
            if (aux.getFuncion() == null) {
                texto = get_cuerpo_bloque_saltoLn(aux.getGrafo().getInicio());
            } else {
                texto = texto + aux.getFuncion() + "\nbegin\n";
                NodoBloque aux2 = aux.getGrafo().getInicio();
                while (aux2 != null) {
                    texto = texto + get_etiquetas_saltoLn(aux2);
                    texto = texto + get_cuerpo_bloque_saltoLn(aux2);
                    aux2 = aux2.getSiguiente();
                }
                texto = texto + "end\n\n";
            }
        }
        try {
            salida.write(texto);
            if (salida != null) {
                salida.flush();
                salida.close();
            }
        } catch (IOException ex) {
            Logger.getLogger(Optimizador.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public boolean optimizacion_mirilla_1(File file) throws FileNotFoundException {
        //luego de haber creado el archivo con el cod 3D, se procede a optimizar por mirilla,
        //la cual, primero se hara la simplificacion algebraica a cada linea
        parsero optimo1 = new parsero(new lexo(new FileInputStream(file)));
        try {
            optimo1.parse();
            if (copia == 0) {
                reescribir_archivo(new File(file.getParent(), file.getName().replace(".ejecutable", "_mirilla1.ejecutable")), optimo1);
                copia++;
            }
            System.out.println("MIRILLA 1");

            int cont_pasadas = 0;
            //se optimiza las globales
            boolean cambio = true;
            while (cambio == true) {
                cambio = mirilla.simplificacion_algebraica(optimo1.getGlobales(), 1);
               // System.out.println("globales");
                cont_pasadas++;
            }

            //se optimiza el cuerpo de las funciones
            Iterator m1 = optimo1.getListaFunciones().iterator();
            while (m1.hasNext()) {
                NodoMirilla aux = (NodoMirilla) m1.next();
                cambio = true;
                while (cambio == true) {
                    cambio = mirilla.simplificacion_algebraica(aux.getLista(), 0);
                   // System.out.println(aux.getLinea());
                    cont_pasadas++;
                    
                }
            }

            reescribir_archivo(file, optimo1);

            int temp = 1 + optimo1.getListaFunciones().size();
            if (cont_pasadas == temp) {
                System.out.println("NO repetir");
                return false;
            }
            System.out.println("repetir");
        } catch (Exception ex) {
            Logger.getLogger(Optimizador.class.getName()).log(Level.SEVERE, null, ex);
        }
        return true;
    }

    public boolean optimizacion_mirilla_2(File file) throws FileNotFoundException {
        //luego de haber creado el archivo con el cod 3D, se procede a optimizar por mirilla,
        //la cual, primero se hara la simplificacion algebraica a cada linea
        parsero optimo1 = new parsero(new lexo(new FileInputStream(file)));
        try {
            optimo1.parse();
            if (copia == 0) {
                reescribir_archivo(new File(file.getParent(), file.getName().replace(".ejecutable", "_mirilla2.ejecutable")), optimo1);
                copia++;
            }
            System.out.println("MIRILLA 2");

            int cont_pasadas = 0;
            //se optimiza las globales
            boolean cambio = true;

            //se optimiza el cuerpo de las funciones
            Iterator m1 = optimo1.getListaFunciones().iterator();
            while (m1.hasNext()) {
                NodoMirilla aux = (NodoMirilla) m1.next();
                cambio = true;
                while (cambio == true) {
                    cambio = mirilla.goto_consecutivos(aux.getLista());
                   // System.out.println(aux.getLinea());
                    cont_pasadas++;
                }
            }

            reescribir_archivo(file, optimo1);

            if (cont_pasadas == optimo1.getListaFunciones().size()) {
                System.out.println("NO repetir");
                return false;
            }
            System.out.println("repetir");
        } catch (Exception ex) {
            Logger.getLogger(Optimizador.class.getName()).log(Level.SEVERE, null, ex);
        }
        return true;
    }

    public boolean optimizacion_mirilla_3(File file) throws FileNotFoundException {
        //luego de haber creado el archivo con el cod 3D, se procede a optimizar por mirilla,
        //la cual, primero se hara la simplificacion algebraica a cada linea
        parsero optimo1 = new parsero(new lexo(new FileInputStream(file)));
        try {
            optimo1.parse();
            if (copia == 0) {
                reescribir_archivo(new File(file.getParent(), file.getName().replace(".ejecutable", "_mirilla3.ejecutable")), optimo1);
                copia++;
            }
            System.out.println("MIRILLA 3");

            int cont_pasadas = 0;
            //se optimiza las globales
            boolean cambio = true;

            //se optimiza el cuerpo de las funciones
            Iterator m1 = optimo1.getListaFunciones().iterator();
            while (m1.hasNext()) {
                NodoMirilla aux = (NodoMirilla) m1.next();
                cambio = true;
                while (cambio == true) {
                    cambio = mirilla.flujos_de_ejecucion(aux.getLista());
                  //  System.out.println(aux.getLinea());
                    cont_pasadas++;
                }
            }

            reescribir_archivo(file, optimo1);

            if (cont_pasadas == optimo1.getListaFunciones().size()) {
                System.out.println("NO repetir");
                return false;
            }
            System.out.println("repetir");
        } catch (Exception ex) {
            Logger.getLogger(Optimizador.class.getName()).log(Level.SEVERE, null, ex);
        }
        return true;
    }

    public boolean optimizacion_mirilla_4(File file) throws FileNotFoundException {
        //luego de haber creado el archivo con el cod 3D, se procede a optimizar por mirilla,
        //la cual, primero se hara la simplificacion algebraica a cada linea
        parsero optimo1 = new parsero(new lexo(new FileInputStream(file)));
        try {
            optimo1.parse();
            if (copia == 0) {
                reescribir_archivo(new File(file.getParent(), file.getName().replace(".ejecutable", "_mirilla4.ejecutable")), optimo1);
                copia++;
            }
            System.out.println("MIRILLA 4");

            int cont_pasadas = 0;
            //se optimiza las globales
            boolean cambio = true;

            //se optimiza el cuerpo de las funciones
            Iterator m1 = optimo1.getListaFunciones().iterator();
            while (m1.hasNext()) {
                NodoMirilla aux = (NodoMirilla) m1.next();
                cambio = true;
                while (cambio == true) {
                    cambio = mirilla.codigo_inalcanzable(aux.getLista());
                  //  System.out.println(aux.getLinea());
                    cont_pasadas++;
                }
            }

            reescribir_archivo(file, optimo1);

            if (cont_pasadas == optimo1.getListaFunciones().size()) {
                System.out.println("NO repetir");
                return false;
            }
            System.out.println("repetir");
        } catch (Exception ex) {
            Logger.getLogger(Optimizador.class.getName()).log(Level.SEVERE, null, ex);
        }
        return true;
    }

    public void generar_imagen(ArrayList<NodoGrafo> lista_grafos, String nombre) throws FileNotFoundException, IOException {
        ListaBloques Block_List = new ListaBloques();

        java.io.FileOutputStream Archivo = new java.io.FileOutputStream(nombre + ".dot", false);

        Archivo.write(("digraph g {\nnode [shape = record];\n").getBytes());

        Iterator it_grafo = lista_grafos.iterator();
        while (it_grafo.hasNext()) {
            NodoGrafo aux = (NodoGrafo) it_grafo.next();
            Block_List.imprimir_grafo(aux.getGrafo(), Archivo);
        }

        Archivo.write("}".getBytes());
        Archivo.close();
        Runtime.getRuntime().exec("dot -Tpng " + nombre + ".dot -o " + nombre + ".png");
    }
    
}
